home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <time.h>
- #include "werr.h"
- #include "dbox.h"
- #include "global.h"
- #include "cmdparse.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "udp.h"
- #include "internet.h"
- #include "timer.h"
- #include "domain.h"
- #include "ip.h"
- #include "misc.h"
-
- #define Domain_OK 0
- #define Domain_Suffix 2
- #define Domain_Timeout 4
- #define Domain_Tries 6
-
- int32 domain_servers[MAX_SERVERS];
- int domain_server_count = 0;
-
- char *domain_suffix = NULLCHAR;
- int domain_timeout = 10;
- int domain_tries = 2;
- int domain_trace = 0;
-
- extern int16 lport;
- extern char *badhost;
-
- struct domain_stat domain_stat;
-
- static int doaddserver(int, char **);
- static int dosuffix(int, char **);
- static int dotimeout(int, char **);
- static int dotries(int, char **);
- static void send_domain_request(struct domain_request *);
- static void recv_domain(struct socket *, int, void *);
- static void timeout_domain(void *);
- static int tokenise_host(char *, char *);
- static int detokenise_host(char *, char *, char *);
- static int32 interpret_a(struct domain_request *, char *, int);
- static int32 interpret_mx(struct domain_request *, char *, int);
-
- struct cmds domcmds[] =
- {
- "addserver", doaddserver, 0, NULLCHAR, NULLCHAR,
- "suffix", dosuffix, 0, NULLCHAR, NULLCHAR,
- "timeout", dotimeout, 0, NULLCHAR, NULLCHAR,
- "tries", dotries, 0, NULLCHAR, NULLCHAR,
- NULLCHAR, NULLFP, 0,
- "domain subcommands: addserver suffix timeout tries",
- NULLCHAR,
- };
-
- int dodomain(int argc, char **argv)
- {
- return subcmd(domcmds, argc, argv);
- }
-
- static int doaddserver(int argc, char **argv)
- {
- int32 n;
-
- if (argc > 1)
- {
- if ((n = resolve(argv[1])) == 0)
- {
- werr(0, badhost, argv[1]);
- return(1);
- }
-
- domain_servers[domain_server_count++] = n;
- }
-
- return(0);
- }
-
- static int dosuffix(int argc, char **argv)
- {
- if (argc > 1)
- {
- if (domain_suffix != NULLCHAR) free(domain_suffix);
- domain_suffix = strdup(argv[1]);
- }
-
- return(0);
- }
-
- static int dotimeout(int argc, char **argv)
- {
- if (argc > 1) domain_timeout = atoi(argv[1]);
- return 0;
- }
-
- static int dotries(int argc, char **argv)
- {
- if (argc > 1) domain_tries = atoi(argv[1]);
- return 0;
- }
-
- void domain_parms(void)
- {
- char Suffix[81];
- dbox d;
-
- if ((d = dbox_new("Dom_Parms")) == NULL)
- return;
-
- dbox_setfield(d, Domain_Suffix, domain_suffix);
- dbox_setnumeric(d, Domain_Timeout, domain_timeout);
- dbox_setnumeric(d, Domain_Tries, domain_tries);
-
- dbox_show(d);
-
- if (dbox_fillin(d) == Domain_OK)
- {
- dbox_getfield(d, Domain_Suffix, Suffix, 80);
- domain_timeout = dbox_getnumeric(d, Domain_Timeout);
- domain_tries = dbox_getnumeric(d, Domain_Tries);
-
- if (domain_suffix != NULLCHAR) free(domain_suffix);
- domain_suffix = strdup(Suffix);
- }
-
- dbox_dispose(&d);
- }
-
- void resolve_a(char *host, char *arg1, char *arg2, void *user, int (*function)(), int (*error)())
- {
- struct domain_request *request;
- char *fullhost;
- int32 n;
-
- if ((n = resolve(host)) != 0)
- {
- (*function)(n, host, arg1, arg2, user);
- return;
- }
-
- if (domain_server_count == 0)
- {
- (*error)(host, "no domain servers known", user);
- return;
- }
-
- if ((request = (struct domain_request *)malloc(sizeof(struct domain_request))) == NULLDOMREQ)
- {
- (*error)(host, "out of memory", user);
- return;
- }
-
- fullhost = malloc(256);
-
- strcpy(fullhost, host);
-
- if (strchr(host, '.') == NULL && domain_suffix != NULLCHAR)
- {
- strcat(fullhost, ".");
- strcat(fullhost, domain_suffix);
- }
-
- if (fullhost[strlen(fullhost) - 1] != '.')
- strcat(fullhost, ".");
-
- request->socket = lport++;
- request->id = clock() & 0xFFFF;
-
- request->domain_t.func = timeout_domain;
- request->domain_t.arg = (void *)request;
-
- request->server = 0;
- request->tries = 0;
- request->type = TYPE_A;
- request->class = CLASS_IN;
- request->function = function;
- request->error = error;
-
- request->host = fullhost;
- request->user = user;
-
- if (arg1 != NULLCHAR)
- request->arg1 = strdup(arg1);
- else
- request->arg1 = NULLCHAR;
-
- if (arg2 != NULLCHAR)
- request->arg2 = strdup(arg2);
- else
- request->arg2 = NULLCHAR;
-
- send_domain_request(request);
- }
-
- void resolve_mx(char *host, void *user, int (*function)(), int (*error)())
- {
- struct domain_request *request;
-
- if (domain_server_count == 0)
- {
- (*error)(host, "no domain servers known", user);
- return;
- }
-
- if ((request = (struct domain_request *)malloc(sizeof(struct domain_request))) == NULLDOMREQ)
- {
- (*error)(host, "out of memory", user);
- return;
- }
-
- if (host[strlen(host) - 1] != '.')
- strcat(host, ".");
-
- request->socket = lport++;
- request->id = clock() & 0xFFFF;
-
- request->domain_t.func = timeout_domain;
- request->domain_t.arg = (void *)request;
-
- request->server = 0;
- request->tries = 0;
- request->type = TYPE_MX;
- request->class = CLASS_IN;
- request->function = function;
- request->error = error;
- request->host = strdup(host);
- request->user = user;
- request->arg1 = NULLCHAR;
- request->arg2 = NULLCHAR;
-
- send_domain_request(request);
- }
-
- static void send_domain_request(struct domain_request *request)
- {
- struct socket fsock, lsock;
- struct mbuf *bp;
- int hostlen;
-
- domain_stat.packets_out[request->type]++;
-
- lsock.address = ip_addr;
- lsock.port = request->socket;
-
- fsock.address = domain_servers[request->server];
- fsock.port = DOMAIN_PORT;
-
- bp = alloc_mbuf(512);
-
- put16(bp->data + 0, request->id);
- bp->data[2] = QR_QUERY | OPCODE_QUERY | RD;
- bp->data[3] = 0x00;
-
- put16(bp->data + 4, 1);
- put16(bp->data + 6, 0);
- put16(bp->data + 8, 0);
- put16(bp->data + 10, 0);
-
- hostlen = tokenise_host(request->host, bp->data + 12);
-
- put16(bp->data + hostlen + 12, request->type);
- put16(bp->data + hostlen + 14, request->class);
-
- bp->cnt = hostlen + 16;
-
- send_udp(&lsock, &fsock, 0, 0, bp, 0, 0, 0);
-
- if (request->tries == 0)
- open_udp(&lsock, recv_domain, request);
-
- set_timer(&request->domain_t, domain_timeout * (1000 / MSPTICK));
-
- start_timer(&request->domain_t);
- }
-
- static void recv_domain(struct socket *socket, int recvcnt, void *arg)
- {
- static char reply[512]; /* UDP maximum size */
- struct domain_request *request;
- struct socket fsock;
- struct mbuf *bp;
- int32 address;
- int size;
-
- recvcnt = recvcnt;
- request = (struct domain_request *)arg;
-
- stop_timer(&request->domain_t);
-
- recv_udp(socket, &fsock, &bp);
- size = dqdata(bp, reply, 512);
-
- if (request->id != get16(reply + 0))
- {
- domain_stat.invalid_id++;
- werr(0, "bad id on received packet");
- return;
- }
-
- domain_stat.packets_in[request->type]++;
-
- switch (request->type)
- {
- case TYPE_A:
- address = interpret_a(request, reply, size);
- break;
- case TYPE_MX:
- address = interpret_mx(request, reply, size);
- break;
- default:
- break;
- }
-
- del_udp(socket);
-
- if (address == 0)
- (*request->error)(request->host, "name not resolvable", request->user);
- else
- (*request->function)(address, request->host, request->arg1, request->arg2, request->user);
-
- free(request->host);
- if (request->arg1 != NULLCHAR) free(request->arg1);
- if (request->arg2 != NULLCHAR) free(request->arg2);
- free(request);
- }
-
- static void timeout_domain(void *arg)
- {
- struct domain_request *request;
- struct socket socket;
-
- request = (struct domain_request *)arg;
-
- domain_stat.timeouts++;
-
- request->server++;
-
- if (request->server == domain_server_count)
- {
- request->tries++;
- request->server = 0;
-
- if (request->tries == domain_tries)
- {
- socket.address = ip_addr;
- socket.port = request->socket;
-
- del_udp(&socket);
-
- (*request->error)(request->host, "no reply from name servers", request->user);
-
- free(request->host);
- if (request->arg1 != NULLCHAR) free(request->arg1);
- if (request->arg2 != NULLCHAR) free(request->arg2);
- free(request);
- return;
- }
- }
-
- send_domain_request(request);
- }
-
- static int32 interpret_a(struct domain_request *request, char *s, int n)
- {
- static char hosta[256];
- static char hostb[256];
- int16 rdlength;
- int16 qdcount;
- int16 ancount;
- int16 type;
- char *t;
- int i;
-
- n = n;
-
- qdcount = get16(s + 4);
- ancount = get16(s + 6);
-
- if (qdcount != 1) return(0);
- if (ancount == 0) return(0);
-
- strcpy(hosta, request->host);
-
- /* Skip QNAME, QTYPE and QCLASS */
- for (t = s + 0x0C; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t += 5;
-
- for (i = 0; i < ancount; i++)
- {
- detokenise_host(t, hostb, s);
-
- for (; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t++;
-
- type = get16(t + 0);
- rdlength = get16(t + 8);
-
- if (strcmp(hosta, hostb) == 0)
- {
- if (type == TYPE_A)
- return(get32(t + 10));
-
- if (type == TYPE_CNAME)
- detokenise_host(t + 10, hosta, s);
- }
-
- t += rdlength + 10;
- }
-
- return(0);
- }
-
- static int32 interpret_mx(struct domain_request *request, char *s, int n)
- {
- static char hosta[256];
- static char hostb[256];
- int16 rdlength;
- int16 preference;
- int16 qdcount;
- int16 ancount;
- int16 nscount;
- int16 arcount;
- int16 type;
- char *t;
- int i;
-
- n = n;
-
- qdcount = get16(s + 4);
- ancount = get16(s + 6);
- nscount = get16(s + 8);
- arcount = get16(s + 10);
- preference = 9999;
-
- if (qdcount != 1) return(0);
- if (ancount == 0) return(0);
-
- strcpy(hosta, request->host);
-
- /* Skip QNAME, QTYPE and QCLASS */
- for (t = s + 0x0C; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t += 5;
-
- for (i = 0; i < ancount; i++)
- {
- detokenise_host(t, hostb, s);
-
- for (; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t++;
-
- type = get16(t + 0);
- rdlength = get16(t + 8);
-
- if (strcmp(hosta, hostb) == 0 && type == TYPE_MX)
- {
- if (get16(t + 10) < preference)
- {
- preference = get16(t + 10);
- detokenise_host(t + 12, hosta, s);
- }
- }
-
- t += rdlength + 10;
- }
-
- for (i = 0; i < nscount; i++)
- {
- for (; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t++;
-
- rdlength = get16(t + 8);
-
- t += rdlength + 10;
- }
-
- for (i = 0; i < arcount; i++)
- {
- detokenise_host(t, hostb, s);
-
- for (; *t != 0x00 && *t != 0xC0; t++);
- if (*t == 0xC0) t++;
- t++;
-
- type = get16(t + 0);
- rdlength = get16(t + 8);
-
- if (strcmp(hosta, hostb) == 0 && type == TYPE_A)
- return(get32(t + 10));
-
- t += rdlength + 10;
- }
-
- return(0);
- }
-
- static int tokenise_host(char *host, char *buffer)
- {
- char *h;
- char *b;
- char *s;
-
- h = strdup(host);
- b = buffer;
-
- s = strtok(h, ".");
-
- while (s != NULLCHAR)
- {
- *b++ = strlen(s);
- while (*s != '\0') *b++ = *s++;
- s = strtok(NULLCHAR, ".");
- }
-
- *b++ = 0;
-
- free(h);
-
- return(b - buffer);
- }
-
- static int detokenise_host(char *thost, char *ahost, char *reply)
- {
- int16 pointer;
- char *hostname;
- int n;
-
- hostname = ahost;
-
- while (*thost != 0)
- {
- if ((*thost & 0xC0) == 0xC0)
- {
- pointer = get16(thost) & 0x3FFF;
- thost = reply + pointer;
- }
- else
- {
- n = *thost++;
- while (n-- > 0) *hostname++ = *thost++;
- *hostname++ = '.';
- }
- }
-
- *hostname++ = '\0';
-
- return(hostname - ahost);
- }
-